#include "example.h"
#include "LightProtocol.h"
#include "LightPanel.h"
#include "Lora.h"
#include "stdlib.h"
#include "Sync.h"

//********************************************************
// 变量定义   
//********************************************************
extern uint8_t      BufferSize;
extern uint8_t      Buffer[BUFFER_SIZE];
uint8_t             BufferSizeTmp;
uint8_t             BufferTmp[BUFFER_SIZE];

extern bool         rxdone;
extern bool         rxtxtimeouterro;
extern uint32_t     global_diff_syn;

uint8_t             updata_flash=0;      //参数更新标识
uint8_t             start_work        =0;
uint8_t             heart_flag        =0;
uint16_t            rcv_lose_cnt      =0;/*基站失联计数，每个心跳周期初始时加1，收到基站心跳清零，
                                           当该数值超过2，则表明基站失联，心跳包改为同步包*/
uint16_t            light_period_cnt  =0;       

//********************************************************
// 定时器：10ms定时
//********************************************************
void Timer_init()
{
  SYS_EnableAPBClock(APB_MASK_GPTIMER3);
  GPTIMER_InitTypeDef tm_init;
  GPTIMER_StructInit(&tm_init);
  tm_init.Autoreload = 10000;
  tm_init.Prescaler = 80;
  GPTIMER_Init(GPTIMER3, &tm_init);
  GPTIMER_SetOnePulseMode(GPTIMER3, GPTIMER_ONEPULSEMODE_SINGLE);
  GPTIMER_EnableCounter(GPTIMER3);

  INT_EnableIRQ(GPTIMER3_IRQn, RTC_PRIORITY);
  GPTIMER_EnableIntUpdate(GPTIMER3);
}

void GPTIMER3_isr()
{
  uint16_t  heart_time=0;
  GPTIMER_ClearFlagUpdate(GPTIMER3);
  GPTIMER_EnableCounter(GPTIMER3);
  
  //
  //动态调整灯全局时钟
  //    当灯时间比基站时间快，需要逐周期调整，直到同步
  //
  light_period_cnt++;
  if( light_period_cnt==((light.param.period[0]<<8)|(light.param.period[1])) )
  {
     light_period_cnt = 0;
     if(global_diff_syn>=4)
     {
        global_diff_syn-=4;
        GLBO_Timer_DEC(4);
     }
     else if(global_diff_syn>0)
     {
        global_diff_syn = 0;
        GLBO_Timer_DEC(global_diff_syn);
     }
  }
  
  //
  //全局时钟累加，返回灯心跳时钟
  //    如果灯心跳时钟到达心跳时刻，触发心跳
  //
  heart_time = GLBO_Timer_INC(1);                                
  if(heart_time_hit(heart_time))                          
  {
     heart_flag = 1;
  }   
  
  //
  //心跳周期起始，基站失联计数+1
  //
  if(heart_time==0)                                       
  {
     rcv_lose_cnt ++;
  }

  //
  //灯板按照模式进行工作
  //
  if(start_work)                                         
  {
     light_work();
     bling_work();
  }
}

//********************************************************
// watchdog_init()
//********************************************************
void watchdog_init(void)
{
  SYS_EnableAPBClock(APB_MASK_WATCHDOG0);
  WDOG_Init(5*SYS_GetPclkFreq()); // 5 second
}

//--------------------------------------------------------
// Uart_init()
// 打印串口初始化，UART0/B115200/8/N/1
//--------------------------------------------------------
void Uart_init(void)
{
  PERIPHERAL_ENABLE(UART,0);
  SYS_EnableAPBClock(APB_MASK_UART0);
  UART_Init(UART0,
            UART_BAUDRATE_115200, 
            UART_LCR_DATABITS_8,
            UART_LCR_STOPBITS_1, 
            UART_LCR_PARITY_NONE, 
            UART_LCR_FIFO_1
            );
}

int putchar(int ch)                                       //printf() 函数需要回调该函数
{
  uint8_t send = ch;
  UART_Send(UART0,&send,1); 
  return 0;
}

//--------------------------------------------------------
// poweron_light_bling()
// 上电闪烁一次指示灯，可以用来观察程序是否重启
//--------------------------------------------------------
void poweron_light_bling()
{
  GPIO_SetHigh(LIGHT_PORT, RED_LIGHT|BLUE_LIGHT);
  UTIL_IdleUs(300000);    //延时
  GPIO_SetLow(LIGHT_PORT, RED_LIGHT|BLUE_LIGHT);
}

//--------------------------------------------------------
// main()
// 
//--------------------------------------------------------
int main(void)
{
  uint8_t  freq=0;
  uint32_t id=0;
  uint8_t  cmd_repeat=0;
  
  Lboard_init();                 //板初始化
  Uart_init();                   //uart初始化（debug用）
  GLBO_Timer_RELOAD();           //全局时钟加载（no init）
  Timer_init();                  //10ms定时器
  FM25Q16_Init();                //Flash初始化，字模存储器
  light.init();                  //灯控初始化
  freq = light.calfreq();        //灯频率计算,灯id为8位数，最高2位数用作频点偏移（2400+fre)MHz
  sx1280_int(freq);              //射频初始化
  poweron_light_bling();         //上电&重启灯光指示
  startRx();                     /*<特别注意：！！！！!
                                 射频接收或发送,在sx1280_int()后需要延迟一段必要时间再进行其它射频操作，否则状态机不稳定，
                                 poweron_light_bling()提供一定延迟>*/
  watchdog_init();       
  start_work=1;                 //灯开始工作
  for(;;)
  {
     WDOG_Feed();
     
     //
     //射频接收处理
     //    读取接收缓存数据
     //    接收数据解析处理
     //    重启接收
     //
     if(rxdone)                  
     { 
        rxdone = false;  
        Radio.GetPayload( Buffer, &BufferSize, BUFFER_SIZE );
        DBUG_SHOW("> receive cmd\r\n");
        
        //收到基站有效指令，基站失联计数清空（判断指令包完整性）
        if( CRC8(Buffer+1,BufferSize-1) == Buffer[0] )
        {
               rcv_lose_cnt = 0;

               //通过指令序号判断，本次指令和上一次指令一样，cmd_repeat置位
               if(Buffer[1]==BufferTmp[1])
               {
                   DBUG_SHOW("> cmd is repeat\r\n");
                   cmd_repeat ++;
               }
               else
               {
                   cmd_repeat   = 0;
                   BufferSizeTmp = BufferSize;
                   memcpy(BufferTmp, Buffer, BufferSize);
               }
               
               if(cmd_repeat<=2)
               {
                  if(light.rxhandle(Buffer,BufferSize))             
                  {
                     if(cmd_repeat>0)
                     {
                        updata_flash = 0;
                     }
                  }
               }

        }
      //   else
      //   {   
      //     DBUG_SHOW("> recieved data erro: ");
      //     for(uint8_t i=0; i<BufferSize; i++)
      //     {
      //          DBUG_SHOW("0x%02x ",Buffer[i]); 
      //     }
      //     DBUG_SHOW("\r\n");
      //   }
        memset( &Buffer, 0x00, BufferSize );
        startRx();
     }

     
     //27字节，SX1280 calculator计算43.6ms,超时时间设置100ms
     if(heart_flag)             
     {
        heart_flag = 0;
        (rcv_lose_cnt>2) ? light.sync(100) : light.heart(100); 
        startRx();
     }
     
     //
     //超时 或 接收错误
     //
     if(rxtxtimeouterro)
     {
        DBUG_SHOW("> receive timeout or erro\r\n");
        rxtxtimeouterro=false;
        startRx();
     }
    
     //
     //参数写flash
     //
     if(updata_flash)     
     {
       updata_flash=0;
       light.savePara();
       freq = light.calfreq();
       sx1280_update_freq(freq);
       update_heart_time_intval(light.param.crowd_num,light.param.group_num,light.param.Tag_num);
     } 
  }
  return 0;
}
